﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace repliback4.Net.Identification {
    /// <summary>
    ///  Repliback Identificator [username@]host[/resource]
    /// </summary>
    public class Rid {
        public enum RidForm { Bare, Full };

        protected static Regex ridRegex = new Regex( @"^((?<username>[^@]+)\@)?(?<host>[^/]+)(/(?<resource>.+))?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture );
        public Username username;
        public Host host;
        public Resource resource;
        public int port;


        public String Username {
            get { return this.username; }
            set { this.username = Identification.Username.Parse( value ); }
        }

        public String Host {
            get { return this.host; }
            set { this.host = Identification.Host.Parse( value ); }
        }

        public String Resource {
            get { return this.resource; }
            set { this.resource = Identification.Resource.Parse( value ); }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="username"></param>
        /// <param name="host"></param>
        /// <param name="resource"></param>
        public Rid ( Username username, Host host, Resource resource ) {
            this.username = username;
            this.host = host;
            this.resource = resource;
        }

        public Rid ( Username username, Host host ) {
            this.username = username;
            this.host = host;
            this.resource = Identification.Resource.Empty;
        }

        public Rid ( Host host ) {
            this.host = host;
            this.resource = Identification.Resource.Empty;
            this.username = Identification.Username.Empty;

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fullRid"></param>
        /// <returns></returns>
        public static Rid Parse ( String fullRid ) {
            Match m = Rid.ridRegex.Match( fullRid );
            Username username = Identification.Username.Parse( m.Groups["username"].Value );
            Resource resource = Identification.Resource.Parse( m.Groups["resource"].Value );
            Host host = Identification.Host.Parse( m.Groups["host"].Value );
            Rid ret = new Rid( username, host, resource );

            int.TryParse( m.Groups["port"].Value, out ret.port );

            return ret;
        }
        public override String ToString ( ) {
            return this.ToString( RidForm.Full );
        }
        public String ToString ( RidForm form ) {
            switch ( form ) {
                default:
                case RidForm.Full:
                    if ( this.username.IsEmpty ) {
                        return String.Format( "{1}{2}", this.username, this.host, this.resource );
                    } else {
                        return String.Format( "{0}@{1}/{2}", this.username, this.host, this.resource );
                    }
                case RidForm.Bare:
                    if ( this.username.IsEmpty ) {
                        return String.Format( "{1}", this.username, this.host, this.resource );
                    } else {
                        return String.Format( "{0}@{1}", this.username, this.host, this.resource );
                    }
            }
        }

        public static implicit operator string ( Rid rid ) {
            return rid.ToString( );
        }
        public static implicit operator Rid ( String rid ) {
            return Rid.Parse( rid );
        }

    }

    public class Host {
        protected static Regex hostRegex = new Regex( @"^([a-z0-9]([a-z0-9_\-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9_\-]*[a-z0-9])+)*)|(localhost)$", RegexOptions.IgnoreCase | RegexOptions.Compiled );
        public String host;
        public Host ( String host ) {
            this.host = host;
        }

        public static Host Parse ( string host ) {
            if ( host != "" ) {
                if ( hostRegex.IsMatch( host ) ) {
                    return new Host( host );
                } else {
                    throw new RidHostParsingException( String.Format( "invalid hostname [{0}]", host ), host );
                }
            } else {
                throw new RidHostParsingException( "empty hostname" );
            }
        }
        public static implicit operator string ( Host host ) {
            return host.ToString( );
        }
        public static implicit operator Host ( string host ) {
            return Host.Parse( host );
        }
        override public String ToString ( ) {
            return this.host;
        }
    }

    public class Username {
        public static Username Empty { get { return new Username( "" ); } }

        protected static Regex usernameRegex = new Regex( @"^[a-z][a-z0-9\.\-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase );
        public String username;

        public Username ( String username ) {
            this.username = username;
        }

        public static Username Parse ( string username ) {
            if ( username != "" ) {
                if ( usernameRegex.IsMatch( username ) ) {
                    return new Username( username );
                } else {
                    throw new RidUsernameParsingException( String.Format( "invalid username [{0}]", username ), username );
                }
            } else {
                return new Username( "" );
            }
        }

        public static implicit operator string ( Username username ) {
            return username.ToString( );
        }
        public static implicit operator Username ( string username ) {
            return Username.Parse( username );
        }

        override public String ToString ( ) {
            return this.username;
        }
        public Boolean IsEmpty {
            get {
                return this.username == null || this.username == "";
            }
        }
    }

    public class Resource {
        protected static Regex resourceRegex = new Regex( @"^[a-z].*" );
        public String resource;

        public static Resource Empty { get { return new Resource( "" ); } }
        public Resource ( String resource ) {
            this.resource = resource;
        }

        public static Resource Parse ( string resource ) {
            if ( resource != "" ) {
                if ( resourceRegex.IsMatch( resource ) ) {
                    return new Resource( resource );

                } else {
                    throw new RidResourceParsingException( String.Format( "Invalid resource [{0}]", resource ), resource );
                }
            } else {
                return new Resource( "" );
            }
        }

        public static implicit operator string ( Resource resource ) {
            return resource.ToString( );
        }

        override public String ToString ( ) {
            return this.resource;
        }

        public Boolean IsEmpty {
            get {
                return this.resource == null || this.resource == "";
            }
        }
    }
    class RidParsingException : Exception {
        protected String value = "";
        public String Value {
            get { return this.value; }
        }
        public RidParsingException ( String message ) : base( message ) { }
        public RidParsingException ( String message, String value )
            : base( message ) {
            this.value = value;
        }
    }

    class RidResourceParsingException : RidParsingException {
        public RidResourceParsingException ( String message ) : base( message ) { }
        public RidResourceParsingException ( String message, String resource ) : base( message, resource ) { }
    }

    class RidHostParsingException : RidParsingException {
        public RidHostParsingException ( String message ) : base( message ) { }
        public RidHostParsingException ( String message, String host ) : base( message, host ) { }
    }
    class RidUsernameParsingException : RidParsingException {
        public RidUsernameParsingException ( String message ) : base( message ) { }
        public RidUsernameParsingException ( String message, String username ) : base( message, username ) { }
    }


    class RidException : Exception {
        public RidException ( String mesage ) : base( mesage ) { }
    }



}
